/*
 * iom8535_user.c
 *
 *  Created on: 21.04.2012
 *      Author: alex
 */
#define GCC_COMPILER

#include "gcc.h"
#include "iar.h"
#include "common.h"
#include "iom8535_user.h"

char timer2_comp_count;
ISR(TIMER2_COMP_vect) {
	timer2_comp_count++;
}

ISR(TIMER1_COMPA_vect) {
	TCCR1B = 0; //stop the timer
	uint16 c_value = TCNT1;
	char next_min_ind = NUM_THREADS;
	uint16 min_interval;
	for(char i=0; i < NUM_THREADS; i++) {
		if (wait_interval[i] != 0) {
			wait_interval[i] -= wait_interval[current_min_thread_indx];
			if (wait_interval[i] > 0) {
				if (next_min_ind == NUM_THREADS || (wait_interval[i] < min_interval)) {
					min_interval = wait_interval[i];
					next_min_ind = i;
				}
			}
		}
	}
	current_min_thread_indx = next_min_ind;
	if (next_min_ind == NUM_THREADS ) {
		//TCCR1B = 0; //stop timer
		TCNT1 = 0; //zero timer
		return;
	} else {
		//TCCR1B = 0; //stop timer
		//uint16 c2_value = TCNT1;
		if (wait_interval[next_min_ind] < 3)
			OCR1A = c_value + 3;
		else
			OCR1A = c_value + wait_interval[next_min_ind];
		TCCR1B = TIMER_PRESCALER;
		return;
	}
}

void pause_thread(char thread_ind, uint16 val){
	TCCR1B = 0; //stop the timer
	wait_interval[thread_ind] = val;
	if (current_min_thread_indx == NUM_THREADS) {
		current_min_thread_indx = thread_ind;
		OCR1A = TCNT1 + val;
		TCCR1B = TIMER_PRESCALER;
		return;
	}
	uint16 c_value;
	if (TCNT1 < OCR1A) {
		c_value = OCR1A - TCNT1;
	} else {
		c_value = 0xFFFF - TCNT1 + OCR1A + 1;
	}
	if (c_value < val) {
		TCCR1B = TIMER_PRESCALER;
		return;
	} else {
		c_value = wait_interval[current_min_thread_indx] - c_value; //already run
		current_min_thread_indx = thread_ind;
		OCR1A = TCNT1 + val;
		for (char i = 0; i < NUM_THREADS; i++){
			if (i != thread_ind)
				wait_interval[i] -= c_value;
		}
		TCCR1B = TIMER_PRESCALER;
		return;
	}
}

uint8 twi_start(){
	TWCR = (1 << TWINT ) | (1 << TWSTA ) | ( 1<< TWEN );
	while ( ! ( TWCR & ( 1 << TWINT ) ) ) { ; };
	if ( ( TWSR & 0xF8 ) != 0x08 ) { //start is occured
		return 1;
	}
	return 0;
}

uint8 twi_stop(){
	  TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN); //send stop bit
	  return 0;
}

uint8 twi_adr(char a) {
	  TWDR = a;
	  TWCR = (1<<TWINT) | (1<<TWEN);
	  while ( ! TWCR&(1<<TWINT) ) {;};
	  if ( ( TWSR & 0xF8 ) == 0x40  ) {
		  return 0; //adress in master recieve mode is sent
	  }
	  if ( ( TWSR & 0xF8 ) == 0x18  ) {
		  return 0; //adress in master transmit mode is sent
	  }
	  return 1; //some error occured
}

uint8 twi_send(uint8 num, uint8*a) {
	char i=0;
	while (i<num){
		TWDR = a[i];
		TWCR = (1<<TWINT) | (1<<TWEN);
		while ( ! TWCR&(1<<TWINT) ) {;};
		if ( ( TWSR & 0xF8 ) != 0x28 ) { //data send is occured
			return 3;
		}
		i++;
	}
	return 0;
}

uint8 twi_send_single(uint8 a) {
	return twi_send(1, &a);
}

uint8 twi_read(uint8 num, uint8 *a) {
	char i=0;
	while (i<num){
		TWCR = (1<<TWINT) | (1<<TWEN);
		while ( ! TWCR&(1<<TWINT) ) {;};
		if ( ( TWSR & 0xF8 ) != 0x50 ) { //data read is occured
			return 3;
		}
		a[i] = TWDR;
		i++;
	}
	return 0;
}

uint8 twi_read_single(uint8 *a){
	return (twi_read(1, a));
}

void twi_init() {
  TWBR = 0x0;
//TWCR |= 1<<TWEA;
  TWSR &= !( ( 1 << TWPS1 ) | ( 1 << TWPS0 ) );

  TWCR &= ! ( 1 << TWIE ); //disable TWI interrupt
  DDRC |= ( 1 << DDC0 ); //SCL signal is output
}

void wait_ticks(char ticks, char presc){
	//wait ticks_t = ticks<<pres
	if (ticks <=0)
		return;
	TCCR2 = 0; //switch off timer2
	TCNT2 = 0; //set tier to 0
	OCR2 = ticks; //set compare unit
	timer2_comp_count = 0; //unset compare event
	TCCR2 = presc; //turn on timer2 on given prescaler
	while (!timer2_comp_count){;} //wait compare match
	TCCR2 = 0; //turn off timer2
	TCNT2 = 0; //clear timer
	return;
}

void timers_init(){
	ASSR &= !(1<<AS2);
	TIMSK = 0; //disable all timers interrupts
	TIMSK |= 1<<OCIE2; //enable compare match interrupt
	//TIMSK &= !(1<<TOIE2); //disable overflow interrupt
	TIMSK |= 1<<OCIE1A; //enable output compare
	TIMSK |= 1<<OCIE1B; //interrupts for A and B
	TCCR2 = 0; //normal mode and switch off timer2
	TCCR1A = 0; //normal mode of counter1
	TCCR1B = 0; //normal mode and switch off timer1
	current_min_thread_indx = NUM_THREADS;
}
